#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Daemon.hpp"
#include <memory>

using namespace ns_tcpserver;
using namespace ns_protocol;

static void Usage(const std::string &process) // 使用手册
{
    std::cout << "\nUsage: " << process << " port\n" << std::endl;
}

// void Debug(int sock) // 测试服务
// {
//     std::cout << "我是一个测试服务, 得到的sock是: " << sock << std::endl;
// }

static Response calculatorHelper(const Request &req) // 计算器助手,把结构化的请求转为结构化的响应
{
    Response resp(0, 0, req._x, req._y, req._op);
    switch (req._op)
    {
    case '+':
        resp._result = req._x + req._y;
        break;
    case '-':
        resp._result = req._x - req._y;
        break;
    case '*':
        resp._result = req._x * req._y;
        break;
    case '/':
        if (0 == req._y)
            resp._code = 1; // 自己定义的类似错误码
        else
            resp._result = req._x / req._y;
        break;
    case '%':
        if (0 == req._y)
            resp._code = 2;
        else
            resp._result = req._x % req._y;
        break;
    default:
        resp._code = 3;
        break;
    }
    return resp;
}

void calculator(int sock) // 网络计算器
{
    std::string inbuffer;
    while (true)
    {
        // std::string str = Recv(sock); // 在这里我们读到了一个请求
        // req.Deserialized(str); // 反序列化, 字节流 -> 结构化
        // Response resp = calculatorHelper(req); // 计算,得到计算结果
        // std::string respString = resp.Serialize(); // 对计算结果进行序列化
        // Send(sock, respString);
        
        bool res = Recv(sock, &inbuffer); // 1. 读到了一个请求
        if(!res) // 读取失败
            break;
        std::string package = Decode(inbuffer); //  2. 协议解析，保证得到一个完整的报文
        if (package.empty())
            continue;
        logMessage(NORMAL, "%s", package.c_str());
        Request req; // 3. 保证该报文是一个完整的报文
        req.Deserialized(package); // 4. 反序列化，字节流 -> 结构化
        Response resp = calculatorHelper(req); // // 5. 业务逻辑(把结构化的请求转为结构化的响应),计算,得到计算结果
        std::string respString = resp.Serialize(); // 6. 对计算结果进行序列化
        respString = Encode(respString); // 7. 添加长度信息，形成一个完整的报文
        Send(sock, respString); // 8. send这里暂时先这样写，多路转接的时候，再谈发送的问题
    }
}

void handler(int signo)
{
    std::cout << "get a signo: " << signo << std::endl;
    exit(0);
}

// ./CalServer port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    MyDaemon();
    // 第一次测试+第三次测试
    std::unique_ptr<TcpServer> server(new TcpServer(atoi(argv[1]))); // 网络功能
    server->BindService(calculator); // 绑定一个服务方法，网络功能和服务进行了解耦
    server->Start();

    // // 第二次测试
    // Request req(1234, 5678, '+');
    // std::string s = req.Serialize(); // 序列化
    // std::cout << s << std::endl;
    // Request temp;
    // temp.Deserialized(s); // 反序列化
    // std::cout << temp._x << std::endl;
    // std::cout << temp._op << std::endl;
    // std::cout << temp._y << std::endl;

    return 0;
}